home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d939.lha / ExtraCmds / source_etc.lha / src / SCD.c < prev    next >
C/C++ Source or Header  |  1993-10-22  |  17KB  |  653 lines

  1. /*   ---------------------------------      -------
  2.  *   |\  | | | | |  |.| |   \|  |/ /|\      |||||||
  3.  *   | | | |/  | |\ |/  |/|  |\ |/  |    ?  ---+---  =<
  4.  *   | | | |   | |  |     |  |  |   |     \qqqqqqqqq/
  5.  *   ---------------------------------  ~~~~~~~~~~~~~~~~
  6.  *  SCD - Smart CD
  7.  *  Copyright (C) 1993 Torsten Poulin
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  *  The author can be contacted by s-mail at
  24.  *    Torsten Poulin
  25.  *    Banebrinken 99, 2, 77
  26.  *    DK-2400 Copenhagen NV
  27.  *    DENMARK
  28.  *
  29.  * $Id: SCD.c,v 37.4 93/04/28 15:11:53 Torsten Exp $
  30.  * $Log:    SCD.c,v $
  31.  * Revision 37.4  93/04/28  15:11:53  Torsten
  32.  * Memory leak plugged.
  33.  * 
  34.  * Revision 37.3  93/04/14  19:01:02  Torsten
  35.  * Allows SCDCOMMAND to be an empty string (implicit CD).
  36.  * Adjusted the size of the ListView gadget to avoid having its
  37.  * label overlap the other gadgets on a lores screen.
  38.  * 
  39.  * Revision 37.2  93/04/14  10:58:16  Torsten
  40.  * Default place to look for table changed to ENV:SCD/Table
  41.  * to comply with the `User Interface Style Guide'.
  42.  * If the local or global environment variable SCDCOMMAND is
  43.  * set, SCD will queue its value (with ACTION_QUEUE) instead
  44.  * of using CurrentDir() and SetCurrentDirName() to circumvent
  45.  * a problem with WShell.
  46.  * 
  47.  * Revision 37.1  93/04/12  23:18:42  Torsten
  48.  * Initial revision
  49.  * 
  50.  */
  51.  
  52. #include <exec/types.h>
  53. #include <exec/memory.h>
  54. #include <exec/lists.h>
  55. #include <exec/nodes.h>
  56. #include <dos/dos.h>
  57. #include <dos/dosasl.h>
  58. #include <dos/var.h>
  59. #include <intuition/intuition.h>
  60. #include <intuition/screens.h>
  61. #include <intuition/gadgetclass.h>
  62. #include <libraries/gadtools.h>
  63. #include <rexx/rexxio.h>
  64.  
  65. #include <clib/dos_protos.h>
  66. #include <clib/exec_protos.h>
  67. #include <clib/utility_protos.h>
  68. #include <clib/gadtools_protos.h>
  69. #include <clib/intuition_protos.h>
  70. #include <clib/graphics_protos.h>
  71. #ifdef __SASC
  72. #include <pragmas/dos_pragmas.h>
  73. #include <pragmas/exec_pragmas.h>
  74. #include <pragmas/utility_pragmas.h>
  75. #include <pragmas/gadtools_pragmas.h>
  76. #include <pragmas/intuition_pragmas.h>
  77. #include <pragmas/graphics_pragmas.h>
  78. #endif
  79. #include <string.h>
  80. #include "tastlib.h"
  81. #include "scd_rev.h"
  82.  
  83.  
  84. #define PROGNAME "SCD"
  85. #define TABNAME "SCDTABLE"
  86. #define DEFNAME "ENV:SCD/Table"
  87. #define CDNAME  "SCDCOMMAND"
  88. #define COPYRIGHT "Copyright © 1993 Torsten Poulin"
  89. #define TEMPLATE "DIR/A"
  90. #define OPT_DIR 0
  91.  
  92. typedef struct {
  93.   struct DosLibrary *DOSBase;
  94.   struct Library    *UtilityBase;
  95.   struct Library    *GadToolsBase;
  96.   struct Library    *IntuitionBase;
  97.   struct Library    *GfxBase;
  98.   struct FileInfoBlock fib;
  99.   struct List *list;
  100.   UBYTE buf[MAXNAMELEN+1];
  101.   UBYTE pattern[(MAXNAMELEN+1)*2];
  102. } Global;
  103.  
  104. typedef struct {
  105.   struct Node nn_Node;
  106.   UBYTE nn_filename[MAXNAMELEN+1];
  107. } NameNode;
  108.  
  109.  
  110. LONG initlist(Global *global);
  111. VOID freelist(Global *global);
  112. LONG insert(UBYTE *filename, Global *global);
  113. LONG SCD(UBYTE *, Global *);
  114. LONG namereq(LONG *, Global *);
  115. VOID handleevents(struct Window *, LONG *, struct Gadget *g[], Global *);
  116. LONG changedir(LONG, Global *);
  117. LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *);
  118.  
  119. struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };
  120. char const versionID[] = VERSTAG;
  121. char const copyright[] = "$COPYRIGHT:" COPYRIGHT "$";
  122.  
  123. LONG entrypoint(VOID)
  124. {
  125.   struct DosLibrary *DOSBase;
  126.   struct RDArgs *args;
  127.   Global *global;
  128.   LONG arg[1];
  129.   LONG rc = RETURN_OK;
  130.  
  131.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
  132.     return RETURN_FAIL;
  133.  
  134.   if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
  135.   {
  136.     PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  137.     rc = RETURN_FAIL;
  138.   }
  139.   else
  140.   {
  141.     global->DOSBase = DOSBase;
  142.     if (!(global->UtilityBase = OpenLibrary("utility.library", 37L)))
  143.       rc = RETURN_FAIL;
  144.     else
  145.     {
  146.       if (!(global->IntuitionBase = OpenLibrary("intuition.library", 37L)))
  147.     rc = RETURN_FAIL;
  148.       else
  149.       {
  150.     if (!(global->GadToolsBase = OpenLibrary("gadtools.library", 37L)))
  151.       rc = RETURN_FAIL;
  152.     else
  153.     {
  154.       if (!(global->GfxBase = OpenLibrary("graphics.library", 37L)))
  155.         rc = RETURN_FAIL;
  156.       else
  157.       {
  158.         arg[OPT_DIR] = 0L;
  159.  
  160.         if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
  161.         {
  162.           printerror(PROGNAME, global);
  163.           rc = RETURN_ERROR;
  164.         }
  165.         else
  166.         {
  167.           rc = SCD((UBYTE *) arg[OPT_DIR], global);
  168.           FreeArgs(args);
  169.  
  170.           if (rc == ERROR_BREAK)
  171.           {
  172.         PrintFault(ERROR_BREAK, NULL);
  173.         rc = RETURN_WARN;
  174.           }
  175.           else if (rc == ERROR_NO_FREE_STORE)
  176.           {
  177.         PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  178.         rc = RETURN_FAIL;
  179.           }
  180.           else if (rc != RETURN_OK)
  181.         printerror(PROGNAME, global);
  182.         }
  183.         CloseLibrary(global->GfxBase);
  184.       }
  185.       CloseLibrary(global->GadToolsBase);
  186.     }
  187.     CloseLibrary(global->IntuitionBase);
  188.       }
  189.       CloseLibrary(global->UtilityBase);
  190.     }
  191.     FreeVec(global);
  192.   }
  193.   CloseLibrary((struct Library *) DOSBase);
  194.   return rc;
  195. }
  196.  
  197.  
  198. LONG initlist(Global *global)
  199. {
  200.   if (!(global->list = AllocVec(sizeof(struct List), MEMF_CLEAR)))
  201.     return ERROR_NO_FREE_STORE;
  202.   /* Initialize list header */
  203.   global->list->lh_Head = (struct Node *) &global->list->lh_Tail;
  204.   global->list->lh_Tail = 0;
  205.   global->list->lh_TailPred = (struct Node *) &global->list->lh_Head;
  206.   return RETURN_OK;
  207. }
  208.  
  209.  
  210. VOID freelist(Global *global)
  211. {
  212.   NameNode *worknode;
  213.   NameNode *nextnode;
  214.  
  215.   worknode = (NameNode *) (global->list->lh_Head);
  216.   while (nextnode = (NameNode *) (worknode->nn_Node.ln_Succ))
  217.   {
  218.     FreeVec(worknode);
  219.     worknode = nextnode;
  220.   }
  221.   FreeVec(global->list);
  222. }
  223.  
  224.  
  225. LONG insert(UBYTE *filename, Global *global)
  226. {
  227.   struct Library *UtilityBase = global->UtilityBase;
  228.   NameNode *namenode;
  229.   struct Node *node;
  230.  
  231.   if (!(namenode = AllocVec(sizeof(NameNode), MEMF_CLEAR)))
  232.     return ERROR_NO_FREE_STORE;
  233.   else
  234.   {
  235.     strcpy(namenode->nn_filename, filename);
  236.     namenode->nn_Node.ln_Name = namenode->nn_filename;
  237.  
  238.     if (global->list->lh_TailPred == (struct Node *) global->list)
  239.       AddHead(global->list, (struct Node *) namenode);
  240.     else
  241.     {
  242.       for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ)
  243.     if (Stricmp(node->ln_Name, filename) >= 0)
  244.       break;
  245.       if (node->ln_Succ)
  246.     Insert(global->list, (struct Node *) namenode, node->ln_Pred);
  247.       else
  248.     AddTail(global->list, (struct Node *) namenode);
  249.     }
  250.  
  251.     return RETURN_OK;
  252.   }
  253. }
  254.  
  255.  
  256. LONG SCD(UBYTE *dir, Global *global)
  257. {
  258.   struct DosLibrary *DOSBase = global->DOSBase;
  259.   LONG number = 0;
  260.   LONG rc = RETURN_OK;
  261.   LONG len;
  262.   UBYTE *lastpart;
  263.   BPTR table;
  264.  
  265.   if (ParsePatternNoCase(dir, global->pattern, strlen(dir)*2+2) < 0)
  266.     return RETURN_FAIL;
  267.  
  268.   if (GetVar(TABNAME, global->buf, MAXNAMELEN, 0) < 0)
  269.     strcpy(global->buf, DEFNAME);
  270.  
  271.   if (!(table = Open(global->buf, MODE_OLDFILE)))
  272.   {
  273.     PrintFault(IoErr(), global->buf);
  274.     return RETURN_FAIL;
  275.   }
  276.  
  277.   if ((rc = initlist(global)) != ERROR_NO_FREE_STORE)
  278.   {
  279.     while (FGets(table, global->buf, MAXNAMELEN+1))
  280.     {
  281.       /* remove newline character */
  282.       len = strlen(global->buf);
  283.       if (len > 0 && global->buf[--len] == '\n')
  284.     global->buf[len] = '\0';
  285.  
  286.       lastpart = FilePart(global->buf);
  287.       if (MatchPatternNoCase(global->pattern, lastpart))
  288.       {
  289.     number++;
  290.     rc = insert(global->buf, global);
  291.       }
  292.     }
  293.  
  294.     if (!rc)
  295.     {
  296.       --number;
  297.       if (number == 0)
  298.     rc = changedir(number, global);
  299.       else if (number > 0)
  300.       {
  301.     rc = namereq(&number, global);
  302.     if (number >= 0)
  303.       rc = changedir(number, global);
  304.       }
  305.       else
  306.       {
  307.     MyPrintf(global, "Can't find %s\n", dir);
  308.     rc = RETURN_FAIL;
  309.       }
  310.     }
  311.     freelist(global);
  312.   }
  313.   Close(table);
  314.   return rc;
  315. }
  316.  
  317.  
  318. /*
  319.  * The following three functions exist because we need global
  320.  * library bases to call the amiga.lib versions and I
  321.  * don't want the bother of building the taglists.
  322.  */
  323.  
  324. struct Gadget *MyCreateGadget(Global *global,
  325.                   ULONG kind,
  326.                   struct Gadget *gad,
  327.                   struct NewGadget *ng,
  328.                   Tag tag1, ...)
  329. {
  330.   struct Library *GadToolsBase = global->GadToolsBase;
  331.   return CreateGadgetA(kind, gad, ng, (struct TagItem *) &tag1);
  332. }
  333.  
  334.  
  335. struct Window *MyOpenWindowTags(Global *global,
  336.                 struct NewWindow *newWindow,
  337.                 Tag tag1, ...)
  338. {
  339.   struct Library *IntuitionBase = global->IntuitionBase;
  340.   return OpenWindowTagList(newWindow, (struct TagItem *) &tag1);
  341. }
  342.  
  343.  
  344. struct Screen *MyOpenScreenTags(Global *global,
  345.                 struct NewScreen *newScr,
  346.                 Tag tag1, ...)
  347. {
  348.   struct Library *IntuitionBase = global->IntuitionBase;
  349.   return OpenScreenTagList(newScr, (struct TagItem *) &tag1);
  350. }
  351.  
  352.  
  353. LONG namereq(LONG *number, Global *global)
  354. {
  355.   struct Library *IntuitionBase = global->IntuitionBase;
  356.   struct Library *GadToolsBase = global->GadToolsBase;
  357.   struct Library *GfxBase = global->GfxBase;
  358.   struct DrawInfo *drawinfo;
  359.   struct Screen *pubscreen;
  360.   struct Screen *screen;
  361.   struct Window *window;
  362.   struct Gadget *glist, *gad;
  363.   struct Gadget *gadgets[3];
  364.   struct NewGadget ng;
  365.   ULONG modeID;
  366.   APTR vi;
  367.  
  368.   glist = NULL;
  369.   if (pubscreen = LockPubScreen(NULL))
  370.   {
  371.     if (drawinfo = GetScreenDrawInfo(pubscreen))
  372.     {
  373.       if ((modeID = GetVPModeID(&(pubscreen->ViewPort))) != INVALID_ID)
  374.       {
  375.     if (screen = MyOpenScreenTags(global, NULL,
  376.                       SA_Pens, (ULONG) (drawinfo->dri_Pens),
  377.                       SA_Depth, drawinfo->dri_Depth,
  378.                       SA_Height, STDSCREENHEIGHT,
  379.                       SA_Width, STDSCREENWIDTH,
  380.                       SA_DisplayID, modeID,
  381.                       SA_Title, VERS " - " COPYRIGHT,
  382.                       SA_Font, &Topaz80,
  383.                       TAG_END))
  384.     {
  385.       if (vi = GetVisualInfoA(screen, NULL))
  386.       {
  387.         gad = CreateContext(&glist);
  388.  
  389.         /* ListView gadget */
  390.         ng.ng_TextAttr = &Topaz80;
  391.         ng.ng_VisualInfo = vi;
  392.         ng.ng_LeftEdge = screen->WBorLeft + 2;
  393.         ng.ng_TopEdge = screen->WBorTop + 1;
  394.         ng.ng_Width = screen->Width - (screen->WBorLeft
  395.                        + screen->WBorRight + 4);
  396.         ng.ng_Height = (screen->Height
  397.                 - ng.ng_TopEdge
  398.                 - (screen->Font->ta_YSize + 1)
  399.                 - 30);
  400.         ng.ng_GadgetText = "_Select directory";
  401.         ng.ng_GadgetID = 0;
  402.         ng.ng_Flags = PLACETEXT_BELOW;
  403.  
  404.         gadgets[0] = gad = MyCreateGadget(global,
  405.                           LISTVIEW_KIND, gad, &ng,
  406.                           GTLV_Labels, global->list,
  407.                           GTLV_ShowSelected, NULL,
  408.                           GTLV_Selected, 0,
  409.                           GT_Underscore, '_',
  410.                           TAG_END);
  411.  
  412.         ng.ng_Height = screen->Font->ta_YSize + 4;
  413.         ng.ng_Width = 100;
  414.         ng.ng_LeftEdge += INTERWIDTH;
  415.         ng.ng_TopEdge = (screen->Height
  416.                  - (screen->WBorTop+(screen->Font->ta_YSize+1))
  417.                  - screen->WBorBottom
  418.                  - ng.ng_Height
  419.                  - INTERHEIGHT);
  420.         ng.ng_GadgetText = "Change _dir";
  421.         ng.ng_Flags = PLACETEXT_IN;
  422.         ng.ng_GadgetID = 1;
  423.         gadgets[1] = gad = MyCreateGadget(global,
  424.                           BUTTON_KIND, gad, &ng,
  425.                           GT_Underscore, '_',
  426.                           TAG_END);
  427.  
  428.         ng.ng_LeftEdge = (screen->Width
  429.                   - screen->WBorLeft - screen->WBorRight - 1
  430.                   - ng.ng_Width
  431.                   - INTERWIDTH);
  432.         ng.ng_GadgetText = "_Cancel";
  433.         ng.ng_GadgetID = 2;
  434.         gadgets[2] = gad = MyCreateGadget(global,
  435.                           BUTTON_KIND, gad, &ng,
  436.                           GT_Underscore, '_',
  437.                           TAG_END);
  438.  
  439.         if (gad)
  440.         {
  441.           if (window = MyOpenWindowTags(global, NULL, 
  442.                         WA_Gadgets, glist,
  443.                         WA_Width, screen->Width,
  444.                         WA_Height,
  445.                         (screen->Height
  446.                          - (screen->WBorTop
  447.                         + (screen->Font->ta_YSize
  448.                            + 1))),
  449.                         WA_RMBTrap, TRUE,
  450.                         WA_SimpleRefresh, TRUE,
  451.                         WA_Activate, TRUE,
  452.                         WA_Backdrop, TRUE,
  453.                         WA_IDCMP, IDCMP_REFRESHWINDOW
  454.                         | IDCMP_VANILLAKEY
  455.                         | LISTVIEWIDCMP
  456.                         | BUTTONIDCMP,
  457.                         WA_CustomScreen, screen,
  458.                         TAG_END))
  459.           {
  460.         GT_RefreshWindow(window, NULL);
  461.         handleevents(window, number, gadgets, global);
  462.         CloseWindow(window);
  463.           }
  464.         }
  465.         FreeGadgets(glist);
  466.         FreeVisualInfo(vi);
  467.       }
  468.       CloseScreen(screen);
  469.     }
  470.       }
  471.       FreeScreenDrawInfo(pubscreen, drawinfo);
  472.     }
  473.     UnlockPubScreen(NULL, pubscreen);
  474.   }
  475.   return RETURN_OK;
  476. }
  477.  
  478.  
  479. VOID handleevents(struct Window *window,
  480.           LONG *number,
  481.           struct Gadget *gadgets[],
  482.           Global *global)
  483. {
  484.   struct Library *GadToolsBase = global->GadToolsBase;
  485.   struct IntuiMessage *imsg;
  486.   struct Gadget *gad;
  487.   struct TagItem lvtags[3];
  488.   LONG n = 0;
  489.   BOOL done = FALSE;
  490.  
  491.   lvtags[0].ti_Tag = GTLV_Selected;
  492.   lvtags[1].ti_Tag = GTLV_Top;
  493.   lvtags[2].ti_Tag = TAG_END;
  494.   lvtags[2].ti_Data = NULL;
  495.  
  496.   while (!done)
  497.   {
  498.     Wait(1 << window->UserPort->mp_SigBit);
  499.  
  500.     while (!done && (imsg = GT_GetIMsg(window->UserPort)))
  501.     {
  502.       switch (imsg->Class)
  503.       {
  504.       case IDCMP_GADGETUP:
  505.     gad = (struct Gadget *) imsg->IAddress;
  506.     switch (gad->GadgetID)
  507.     {
  508.     case 0: n = imsg->Code; break;
  509.     case 1: *number = n; done = TRUE; break;
  510.     case 2: *number = -1; done = TRUE; break;
  511.     }
  512.     break;
  513.       case IDCMP_VANILLAKEY:
  514.     switch (imsg->Code)
  515.     {
  516.     case 'D':
  517.     case 'd': *number = n; done = TRUE; break;
  518.     case 'C':
  519.     case 'c': *number = -1; done = TRUE; break;
  520.     case 'S':
  521.       if (--n < 0)
  522.         n = 0;
  523.       lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
  524.       GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
  525.       break;
  526.     case 's':
  527.       if (++n > *number)
  528.         n = *number;
  529.       lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
  530.       GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
  531.       break;
  532.     }
  533.     break;
  534.       case IDCMP_REFRESHWINDOW:
  535.     GT_BeginRefresh(window);
  536.     GT_EndRefresh(window, TRUE);
  537.     break;
  538.       }
  539.       GT_ReplyIMsg(imsg);
  540.     }
  541.   }
  542. }
  543.  
  544.  
  545. LONG changedir(LONG number, Global *global)
  546. {
  547.   struct DosLibrary *DOSBase = global->DOSBase;
  548.   struct Node *node;
  549.   LONG rc = RETURN_OK;
  550.   LONG n = 0;
  551.   BPTR lock;
  552.  
  553.   for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ, n++)
  554.     if (n == number)
  555.       break;
  556.  
  557.   if (lock = Lock(node->ln_Name, SHARED_LOCK))
  558.   {
  559.     if (Examine(lock, &global->fib)
  560.         && global->fib.fib_DirEntryType > 0
  561.         && global->fib.fib_DirEntryType != ST_SOFTLINK)
  562.     {
  563.       if (GetVar(CDNAME, global->buf, MAXNAMELEN, 0) >= 0)
  564.     rc = queuecommand(global->buf, node->ln_Name, global);
  565.       else
  566.       {
  567.     lock = CurrentDir(lock);
  568.     SetCurrentDirName(node->ln_Name);
  569.       }
  570.     }
  571.     else
  572.       rc = RETURN_ERROR;
  573.     UnLock(lock);
  574.   }
  575.   else
  576.     rc = RETURN_ERROR;
  577.   return rc;
  578. }
  579.  
  580.  
  581. /*
  582.  * Send ACTION_QUEUE packet to the handler associated with stdin.
  583.  * The method was learned by `reverse engineering' the QUEUE command
  584.  * shipped with the ConMan 1.3 console handler.
  585.  * Information kindly provided by Kristian Nielsen (bombadil@diku.dk)
  586.  * (and ultimately Bill Hawes, author of ARexx, ConMan, and WShell :-) ).
  587.  */
  588.  
  589. LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *global)
  590. {
  591.   struct DosLibrary *DOSBase = global->DOSBase;
  592.   struct FileHandle *console_fh;
  593.   struct MsgPort *destport;
  594.   struct MsgPort *port;
  595.   struct Process *process;
  596.   UBYTE *line;
  597.   LONG line_len;
  598.   BPTR console_fh_bptr;
  599.   LONG rc = RETURN_OK;
  600.  
  601.   /* Add 1 for space, 2 for quotes, 1 for '\n', and 1 for '\0' */
  602.   line_len = strlen(cmd) + strlen(arg) + 5;
  603.   if (!(line = AllocVec(line_len, 0L)))
  604.     return ERROR_NO_FREE_STORE;
  605.  
  606.   /* Build command line */
  607.   strcpy(line, cmd);
  608.   strcat(line," \"");
  609.   strcat(line, arg);
  610.   strcat(line, "\"\n");
  611.  
  612.   /* Get process and process msgport. */
  613.   process = (struct Process *) FindTask(NULL);
  614.   port = &process->pr_MsgPort;
  615.   
  616.   /*
  617.    * ACTION_QUEUE works like ACTION_READ and ACTION_WRITE.
  618.    * It takes three args: The fh_Arg1 field of the file handle
  619.    * (NOT the file handle itself), the start of the data to queue, and
  620.    * the number of bytes to queue.
  621.    *
  622.    * Since we need a file handle, we cannot just call GetConsoleTask().
  623.    * The ConMan command 'queue' uses the pr_CIS field of the process
  624.    * structure. We simply use Input().
  625.    */
  626.  
  627.   console_fh_bptr = Input();    /* Could use process->pr_CIS */
  628.   if (!console_fh_bptr)
  629.   {
  630.     MyPrintf(global, "%s: Cannot queue %s\n", PROGNAME, line);
  631.     rc = RETURN_FAIL;
  632.   }
  633.   else
  634.   {
  635.     console_fh = BADDR(console_fh_bptr); /* Convert to C pointer. */
  636.     if (!console_fh->fh_Type)
  637.     {
  638.       MyPrintf(global,
  639.            "%s: Input stream not associated with handler process\n",
  640.            PROGNAME);
  641.       rc = RETURN_FAIL;
  642.     }
  643.     else
  644.     {
  645.       destport = console_fh->fh_Type;
  646.       DoPkt(destport, ACTION_QUEUE, console_fh->fh_Arg1,
  647.         (LONG) line, line_len, 0L, 0L);
  648.     }
  649.   }
  650.   FreeVec(line);
  651.   return rc;
  652. }
  653.